package com.sys.controller;

import com.alibaba.fastjson.JSONObject;
import com.sys.entity.SysPersonal;
import com.sys.entity.SysRole;
import com.sys.entity.SysUser;
import com.sys.entity.SysUserRole;
import com.sys.service.SysPersonalService;
import com.sys.service.SysRoleService;
import com.sys.service.SysUserRoleService;
import com.sys.service.SysUserService;
import com.sys.shiro.RetryLimitHashedCredentialsMatcher;
import com.sys.utils.ShiroUtils;
import com.sys.utils.Utils;
import com.bhudy.base.QueryFilter;
import com.bhudy.enums.Relation;
import com.bhudy.exception.SysException;
import com.bhudy.exception.SysExceptionCode;
import com.bhudy.utils.ResponseResult;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @Author bhudy
 * @Description 用户controller
 * @Date 2019-10-30 23:09:37
 */
@RestController
public class SysUserController {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysPersonalService sysPersonalService;
    @Autowired
    private RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher;
    @Autowired
    private SysRoleService sysRoleService;

    /**
     * 用户登录接口
     *
     * @param request   HttpServletRequest
     * @param response  HttpServletResponse
     * @param json      body里面的账号和密码
     * @param loginCode 账号{bhy}
     * @param password  密码{bhy00000}
     * @return 状态码和登陆成功的token
     */
    @PostMapping(value = "/api/v1/sysLogin")
    public ResponseResult login(HttpServletRequest request, HttpServletResponse response, @RequestBody String json, String loginCode, String password) {
        SysUser sysUser = sysUserService.login(json, loginCode, password);

        //登录成功之后跳转到原url
        String url = "/";
        SavedRequest savedRequest = WebUtils.getSavedRequest(request);
        if (savedRequest != null) {
            url = savedRequest.getRequestUrl();
        }

        Map<String, String> cookieMap = new HashMap<>();
        cookieMap.put("userAgent", request.getHeader("user-agent"));
        cookieMap.put("remoteAddr", request.getRemoteAddr());
        cookieMap.put("uuid", UUID.randomUUID().toString());
        cookieMap.put("sessionId", ShiroUtils.getSessionId());

        String access_token = ShiroUtils.getSessionId();// AesCBCUtil.encrypt(AesCBCUtil.encrypt(JSONObject.toJSONString(cookieMap)));

        Cookie cookie = new Cookie("access_token", access_token);
        cookie.setHttpOnly(false);
        cookie.setPath("/");
        response.addCookie(cookie);

        cookie = new Cookie("user_id", sysUser.getUserId().toString());
        cookie.setHttpOnly(false);
        cookie.setPath("/");
        response.addCookie(cookie);

        cookie = new Cookie("user_name", sysUser.getUserName());
        cookie.setHttpOnly(false);
        cookie.setPath("/");
        response.addCookie(cookie);

        cookie = new Cookie("res_personal_id", sysUser.getSysPersonalId().toString());
        cookie.setHttpOnly(false);
        cookie.setPath("/");
        response.addCookie(cookie);

        Map<String, String> resultData = new HashMap<>();
        resultData.put("url", url);
        resultData.put("access_token", access_token);
        resultData.put("user_id", sysUser.getUserId().toString());
        resultData.put("user_name", sysUser.getUserName());
        resultData.put("res_personal_id", sysUser.getSysPersonalId().toString());

        return ResponseResult.printMapJson(SysExceptionCode.CODE_10001.getCode(), resultData);
    }

    /**
     * 退出登录接口
     *
     * @return 退出成功的状态码
     */
    @GetMapping(value = "/api/v1/sysLogout")
    public ResponseResult sysLogout() {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            subject.logout();
        }
        return ResponseResult.printMapJson(SysExceptionCode.CODE_10002.getCode());
    }

    /**
     * 获取用户信息
     *
     * @param page          页数{1}
     * @param limit         显示数量{10}
     * @param loginCode     登陆账号{bhy}
     * @param sysPersonalId 使用人Id{1}
     * @return 用户信息列表里面包含使用人信息和角色信息
     */
    @GetMapping(value = "/api/v1/sysUsers")
    public ResponseResult getAll(Integer page, Integer limit, String loginCode, Long sysPersonalId) {
        QueryFilter queryFilter = new QueryFilter().and("status", Relation.NOT_EQUAL, 1);
        if (page != null && limit != null) queryFilter.limit(--page, limit);
        if (loginCode != null && !loginCode.equals("")) queryFilter.andLike("loginCode", "%" + loginCode + "%");
        if (sysPersonalId != null) queryFilter.and("sysPersonalId", sysPersonalId);
        int count = sysUserService.count(queryFilter);
        List<SysUser> sysUserList = sysUserService.findList(queryFilter);

        List<SysPersonal> sysPersonalList = sysPersonalService.findAll();
        Map<Long, SysPersonal> resPersonalMapping = new HashMap<>();
        if (Utils.isBlank(sysPersonalList)) {
            for (SysPersonal sysPersonal : sysPersonalList) {
                resPersonalMapping.put(sysPersonal.getId(), sysPersonal);
            }
        }

        List<SysUserRole> sysUserRoleList = sysUserRoleService.findAll();
        List<SysRole> sysRoleList = sysRoleService.findAll();
        Map<Long, SysRole> sysRoleMapping = new HashMap<>();
        for (SysRole sysRole : sysRoleList) {
            sysRoleMapping.put(sysRole.getRoleId(), sysRole);
        }

        Map<Long, List<SysUserRole>> sysUserRoleMapping = new HashMap<>();
        if (Utils.isBlank(sysUserRoleList)) {
            for (SysUserRole sysUserRole : sysUserRoleList) {
                sysUserRole.setSysRole(sysRoleMapping.get(sysUserRole.getRoleId()));
                List<SysUserRole> userRoleList;
                if (sysUserRoleMapping.containsKey(sysUserRole.getUserId())) {
                    userRoleList = sysUserRoleMapping.get(sysUserRole.getUserId());
                } else {
                    userRoleList = new ArrayList<>();
                }
                userRoleList.add(sysUserRole);
                sysUserRoleMapping.put(sysUserRole.getUserId(), userRoleList);
            }
        }

        List<Map<String, Object>> sysUserMapList = new ArrayList<>();
        if (Utils.isBlank(sysUserList)) {
            for (SysUser sysUser : sysUserList) {
                Map<String, Object> sysUserMap = JSONObject.parseObject(JSONObject.toJSONString(sysUser), Map.class);
                sysUserMap.remove("password");
                sysUserMap.remove("salt");
                sysUserMap.put("sysRoleList", sysUserRoleMapping.get(sysUser.getUserId()));
                sysUserMap.put("resPersonal", resPersonalMapping.get(sysUser.getSysPersonalId()));
                sysUserMapList.add(sysUserMap);
            }
        }

        return ResponseResult.printMapJson(0, count, sysUserMapList);
    }

    @GetMapping(value = "/api/v1/sysUserJson")
    public ResponseResult getAllJson(String userName, Integer notStatus, Boolean isLimit) {
        String sql = "select " + sysUserService.keywords("user_id", "user_name") + " from sys_user where 1 = 1";
        List<Object> argList = new ArrayList<>();
        if (notStatus != null) {
            sql += " and `status` != ?";
            argList.add(notStatus);
        }
        if (userName != null && !userName.equals("")) {
            sql += " and user_name like ?";
            argList.add("%" + userName + "%");
        }
        if (isLimit != null && isLimit) sql += " limit 0,50";
        return ResponseResult.printMapJson(0, sysPersonalService.findMapList(sql, argList.toArray()));
    }

    @GetMapping(value = "/api/v1/sysUser")
    public ResponseResult get(Long userId) {
        return ResponseResult.printMapJson(0, sysUserService.get(userId));
    }

    @PostMapping(value = "/api/v1/sysUser")
    public ResponseResult insert(@RequestBody String json) {
        SysUser sysUser = JSONObject.parseObject(json, SysUser.class);
        String salt = UUID.randomUUID().toString();
        String loginCode = sysUser.getLoginCode();
        sysUser.setSalt(salt);
        String password = "";
        for (int i = loginCode.length(); i < 8; i++) {
            password += "0";
        }
        sysUser.setPassword(Utils.md5(loginCode + password, salt));
        sysUser.setPwdSecurityLevel(0);

        Long resPersonalId = sysUser.getSysPersonalId();
        if (resPersonalId != null) {
            if (resPersonalId.equals("")) {
                sysUser.setUserName("");
            } else {
                SysPersonal sysPersonal = sysPersonalService.get(resPersonalId);
                sysUser.setUserName(sysPersonal.getName());
            }
        }

        sysUserService.insert(sysUser);
        return ResponseResult.printMapJson(0, sysUser.getUserId());
    }

    @PutMapping(value = "/api/v1/sysUser")
    public ResponseResult update(@RequestBody String json) {
        SysUser sysUser = JSONObject.parseObject(json, SysUser.class);
        if (sysUser == null) throw new SysException(SysExceptionCode.CODE_40003);

        if (sysUser.getPassword() != null && sysUser.getPassword().length() < 8)
            throw new SysException(SysExceptionCode.CODE_40030);

        Long resPersonalId = sysUser.getSysPersonalId();
        if (resPersonalId != null) {
            if (resPersonalId.equals("")) {
                sysUser.setUserName("");
            } else {
                SysPersonal sysPersonal = sysPersonalService.get(resPersonalId);
                sysUser.setUserName(sysPersonal.getName());
            }
        }

        if (sysUser.getStatus() != null) {
            sysUser.setFreezeDate(new Date());
        }
        sysUser.setPassword(null);
        sysUser.setSalt(null);
        /*if (sysUser.getPassword() != null) {
            String salt = UUID.randomUUID().toString();
            sysUser.setSalt(salt);
            sysUser.setPassword(Utils.md5(sysUser.getPassword(), salt));
        }*/
        sysUserService.update(sysUser);
        return ResponseResult.printMapJson(0, sysUser.getUserId());
    }

    /**
     * 修改密码
     * 只有账号状态是正常的（0）,才能修改密码
     * 3个参数必填loginCode、newPassword、password
     * newPassword长度必须大于等于8位
     * 密码验证必须通过
     *
     * @param json {
     *             "loginCode":"bhy",
     *             "newPassword":"bhy00000",
     *             "password":"bhy11111"
     *             }
     * @return 处理结果的状态码
     */
    @PutMapping(value = "/api/v1/updatePwd")
    public ResponseResult updatePwd(@RequestBody String json) {
        Map<String, Object> sysUserMap = JSONObject.parseObject(json, Map.class);

        String loginCode = String.valueOf(sysUserMap.get("loginCode"));
        String newPassword = String.valueOf(sysUserMap.get("newPassword"));
        String password = String.valueOf(sysUserMap.get("password"));

        if (loginCode == null || newPassword == null || password == null ||
                loginCode.equals("") || newPassword.equals("") || password.equals(""))
            throw new SysException(SysExceptionCode.CODE_40003);
        if (newPassword.length() < 8) throw new SysException(SysExceptionCode.CODE_40030);

        QueryFilter queryFilter = new QueryFilter();
        queryFilter.and("loginCode", loginCode);
        SysUser sysUser = sysUserService.find(queryFilter);
        if (sysUser == null) throw new SysException(SysExceptionCode.CODE_40002);
        if (sysUser.getStatus() != SysUser.statusCode0) throw new SysException(SysExceptionCode.CODE_40031);

        sysUser.setPwdSecurityLevel(Utils.checkPasswordStrength(newPassword));

        if (!Utils.md5(password, sysUser.getSalt()).equals(sysUser.getPassword()))
            throw new SysException(SysExceptionCode.CODE_40009);

        sysUser.setPassword(Utils.md5(newPassword, sysUser.getSalt()));
        sysUser.setPwdUpdateDate(new Date());

        return ResponseResult.printMapJson(0, sysUserService.update(sysUser));
    }


    /**
     * 重置密码
     *
     * @param json {"loginCode":"bhy"}
     * @return 处理结果的状态码
     */
    @PutMapping(value = "/api/v1/resetPwd")
    public ResponseResult resetPwd(@RequestBody String json) {
        Map<String, Object> sysUserMap = JSONObject.parseObject(json, Map.class);

        String loginCode = String.valueOf(sysUserMap.get("loginCode"));

        if (loginCode == null) throw new SysException(SysExceptionCode.CODE_40003);

        QueryFilter queryFilter = new QueryFilter();
        queryFilter.and("loginCode", loginCode);
        SysUser sysUser = sysUserService.find(queryFilter);
        if (sysUser == null) throw new SysException(SysExceptionCode.CODE_40002);
        if (sysUser.getStatus() != SysUser.statusCode2) throw new SysException(SysExceptionCode.CODE_40031);

        String salt = UUID.randomUUID().toString();
        sysUser.setSalt(salt);
        String password = "";
        for (int i = loginCode.length(); i < 8; i++) {
            password += "0";
        }

        sysUser.setPwdSecurityLevel(0);
        sysUser.setPassword(Utils.md5(loginCode + password, salt));
        sysUser.setStatus(SysUser.statusCode0);
        sysUser.setPwdUpdateDate(new Date());
        sysUser.setFreezeCause("");

        retryLimitHashedCredentialsMatcher.unlockAccount(loginCode); // 重置缓存里面的数据

        return ResponseResult.printMapJson(0, sysUserService.update(sysUser));
    }

    @DeleteMapping(value = "/api/v1/sysUsers")
    public ResponseResult delete(@RequestBody String json) {
        return ResponseResult.printMapJson(0, sysUserService.delete(JSONObject.parseObject(json, Long[].class)));
    }

}
